"""__NATIVE__

#include <string.h>

#include "fixedQueue.h"
#include "irq.h"


typedef struct
{
    char event[32];
    int data;
} pairEventData;


static fixedQueue eventmanager_queue;    // Queue of events
static pPmObj_t pumpEvents_func;         // Pointer to pumpEvents function


static void interruptions_int_handler(registers_t* regs)
{
    // Add event to queue
    pairEventData pair;

    snprintf(pair.event, sizeof(pair.event)-1, "IRQ/%d", regs->int_no - IRQ0);
    pair.data = regs->err_code;

    fixedQueue_append(&eventmanager_queue, &pair);

    // Pump events from queue (on a new thread)
    interp_addThread((pPmFunc_t)pumpEvents_func);
}
"""


from dict import has_key

_events = {}
_pumping = False;


def _init(func):
    """__NATIVE__

    static pairEventData eventmanager_queue_items[10];
    int i = 0;

    PmReturn_t retval = PM_RET_OK;
    pPmObj_t pf;

    /* If wrong number of args, raise TypeError */
    if (NATIVE_GET_NUM_ARGS() != 1)
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    /* If arg is not a function, raise TypeError */
    pf = NATIVE_GET_LOCAL(0);
    if (OBJ_GET_TYPE(pf) != OBJ_TYPE_FXN)
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    pumpEvents_func = pf;

    // Init events queue
    fixedQueue_init(&eventmanager_queue, eventmanager_queue_items,
                    sizeof(pairEventData));
    eventmanager_queue.capacity = 10;    // Hugly hack

    // Init interruption handlers
//    // Exceptions
//    for(; i < 32; i++)
//        irq_handler_register(i, &interruptions_exc_handler);

    // IRQs except PIT and keyboard
    i = 33;
    for(; i < 48; i++)
        irq_handler_register(i, &interruptions_int_handler);

    NATIVE_SET_TOS(PM_NONE);
    return retval;
    """
    pass


def init():
    _init(pumpEvents)


def attach(event, func):
    _events[event] = func


def deattach(event):
    del _events[event]


def _queue_isEmpty():
    """__NATIVE__

    PmReturn_t retval = PM_RET_OK;

    /* If wrong number of args, raise TypeError */
    if (NATIVE_GET_NUM_ARGS() != 0)
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    if(fixedQueue_isEmpty(&eventmanager_queue))
        NATIVE_SET_TOS(PM_TRUE);
    else
        NATIVE_SET_TOS(PM_FALSE);

    return retval;
    """
    pass

def _queue_popEvent():
    """__NATIVE__

    pairEventData pair;

    PmReturn_t retval = PM_RET_OK;
    pPmObj_t ptup;
    pPmObj_t pevent;
    pPmObj_t pdata;

    /* If wrong number of args, raise TypeError */
    if (NATIVE_GET_NUM_ARGS() != 0)
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    pair = *(pairEventData*)fixedQueue_head(&eventmanager_queue);
    fixedQueue_pop(&eventmanager_queue);

    /* Allocate a tuple to store the return values */
    retval = tuple_new(2, &ptup);
    PM_RETURN_IF_ERROR(retval);

    char* event = pair.event;
    retval = string_new(&event, &pevent);
    PM_RETURN_IF_ERROR(retval);

    retval = int_new(pair.data, &pdata);
    PM_RETURN_IF_ERROR(retval);

    /* Put the two values in the tuple */
    ((pPmTuple_t)ptup)->val[0] = pevent;
    ((pPmTuple_t)ptup)->val[1] = pdata;

    /* Return the tuple on the stack */
    NATIVE_SET_TOS(ptup);

    return retval;
    """
    pass


def pumpEvents():
    print "pumpEvents"
    # Don't start pumping if we are doing it yet
    if pumping:
        return

    pumping = True;

    # Pump events until there's no more
    while not _queue_isEmpty():
        event, data = _queue_popEvent()
        print "_events =",_events
        print "event =", event
        print "data =", data
        if has_key(_events, event):
            _events[event](data)

    # Say we finished to pump events
    pumping = False;
